<?
class ZPlus_DataTable
{
  public static function htmlFromArray($body, $head, $footer = null, $attr = array())
  {
    $t  = '<table';
    if (!empty($attr))
    {
      foreach ($attr as $k => $v)
        $t .= ' '.$k.'="'.$v.'"';
    }
    $t .= '>';

    $t .= '<tr>';
    foreach ($head as &$v)
    {
      $t .= '<th>'.$v['label'].'</th>';
    }
    $t .= '</tr>';

    if (!empty($body))
    {
      foreach ($body as &$r)
      {
        $t .= '<tr>';
        foreach ($head as &$h)
        {
          if (!isset($r[$h['key']]))
            $content = '&nbsp;';
          else if (empty($h['raw']))
            $content = htmlspecialchars($r[$h['key']]);
          else
            $content = $r[$h['key']];
          if (isset($h['align']))
            $t .= '<td align="'.$h['align'].'">'.$content.'</td>';
          else
            $t .= '<td>'.$content.'</td>';
        }
        $t .= '</tr>';
      }
    }
    else
    {
      $t .= '<tr><td class="nodata" colspan="'.count($head).'">no data</td></tr>';
    }

    if (!empty($footer))
    {
      $t .= '<tr>';
      foreach ($footer as &$v)
      {
        $fattr = '';
        if (isset($v['colspan'])) $fattr .= ' colspan="'.$v['colspan'].'"';
        if (isset($v['align']))   $fattr .= ' align="'.$v['align'].'"';
        $t .= '<th'.$fattr.'>'.$v['display'].'</th>';
      }
      $t .= '</tr>';
    }

    $t .= '</table>';
    return $t;
  }

  public function __construct($head, $opts = array())
  {
    $this->head = $head;
    $this->page_size = isset($opts['page_size']) ? $opts['page_size'] : 25;
    if (isset($opts['page_opts']))
      $this->page_opts = $opts['page_opts'];
  }

  public function modifier($modifier)
  {
    $this->modifier = $modifier;
  }

  public function bind($db_alias, $sql, $sql_count, array $sql_params = array())
  {
    $this->db_alias = $db_alias;
    $this->sql = $sql;
    $this->sql_count = $sql_count;
    $this->sql_params = $sql_params;
  }

  public function count()
  {
    $db = Dbz::db($this->db_alias);
    return $db->fetchOne($this->sql_count, $this->sql_params);
  }

  public function query($rec_count = null, $rec_start = 0)
  {
    $db = Dbz::db($this->db_alias);
    $sql = $this->sql;
    if ($rec_count !== null)
    {
      $sql .= ' LIMIT ';
      if (!empty($rec_start))
      {
        $sql .= $rec_start.',';
      }
      $sql .= $rec_count;
    }
    $r = $db->fetchAll($sql, $this->sql_params);
    if (!empty($this->modifier))
    {
      call_user_func($this->modifier, &$r);
    }
    return $r;
  }

  public function html($rec_count = null, $rec_start = 0)
  {
    $body = $this->query($rec_count, $rec_start);
    return self::htmlFromArray($body, $this->head);
  }

  public function javascript($element_id, $ajax_url)
  {
    $head   = array();
    $fields = array();
    foreach ($this->head as &$v)
    {
      $h = 'key:"'.$v['key'].'"';
      if (isset($v['label']))  $h .= ',label:"'.$v['label'].'"';
      if (isset($v['number'])) $h .= ',formatter:"number"';
      if (isset($v['align']))  $h .= ',className:"align-'.$v['align'].'"';
      $head[]   = '{'.$h.'}';
      $f = 'key:"'.$v['key'].'"';
      $fields[] = '{'.$f.'}';
    }
    $head   = implode($head, ',');
    $fields = implode($fields, ',');

    $p = strpos($ajax_url, '?');
    if ($p === false) $ajax_url .= '?';
    else if ($p != strlen($ajax_url)) $ajax_url .= '&';

    if (isset($this->page_opts))
    {
      $page_opts = <<<EOD
      template: YAHOO.widget.Paginator.TEMPLATE_ROWS_PER_PAGE,
      rowsPerPageOptions: [{$this->page_opts}],
EOD;
    }
    else
    {
      $page_opts = '';
    }

    $javascript = <<<EOD
YUI().use("yui2-event", "yui2-dragdrop", "yui2-paginator", "yui2-datatable", "yui2-connection", "yui2-json", function(Y) {

  var YAHOO = Y.YUI2;

  var header = [$head];

  var source = new YAHOO.util.DataSource("$ajax_url");
  source.responseType = YAHOO.util.DataSource.TYPE_JSON;
  source.responseSchema = {
    resultsList: "records",
    fields: [$fields],
    metaFields: { totalRecords: "totalRecords", },
  };

  var config = {
    initialRequest: "results={$this->page_size}",
    dynamicData: true,
    paginator: new YAHOO.widget.Paginator({
      rowsPerPage: {$this->page_size},
//      pageLinks: 5,
      $page_opts
    }),
  };

  var table = new YAHOO.widget.DataTable("$element_id", header, source, config);
  table.handleDataReturnPayload = function(oRequest, oResponse, oPayload) {
    oPayload.totalRecords = oResponse.meta.totalRecords;
    return oPayload;
  }

});
EOD;
    return $javascript;
  }

  public function json($rec_count = null, $rec_start = 0)
  {
    $json = array();
    $json['totalRecords'] = $this->count();
    $json['records'] = $this->query($rec_count, $rec_start);
    return json_encode($json);
  }
}
